
#define DOHOME_LOG_LVL          DOHOME_LOG_LVL_DEBUG
#define DOHOME_LOG_TAG          "hal_network"

#include <stdio.h>
#include <stdlib.h>

#include "dohome_log.h"
#include "dohome_cfg.h"

#include "dohome_type.h"
#include "dohome_error_code.h"

#include "dohome_hal_wifi.h"
#include "dohome_hal_network.h"


#include "http_client.h"

#include "lwip/udp.h"
#include <lwip/def.h>
#include <lwip/netdb.h>
#include <lwip/sockets.h>

#include "wm_osal.h"
#include "wm_http_client.h"

#if (defined(DOHOME_CFG_NETWORK_USE_TASK) && DOHOME_CFG_NETWORK_USE_TASK == 1)

#define CONFIG_HTTP_STACK_SIZE          4096
#define CONFIG_HTTP_STACK_PRIORITY      14
#define CONFIG_HTTP_MAX_CLIENT          2

#define CONFIG_TCPC_STACK_SIZE          2048
#define CONFIG_TCPC_STACK_PRIORITY      14
#define CONFIG_TCPC_MAX_CLIENT          2

#define CONFIG_TCPS_MAX_SERVER          2
#define CONFIG_TCPS_STACK_SIZE          2048
#define CONFIG_TCPS_STACK_PRIORITY      14
#define CONFIG_TCPS_MAX_CLIENT          3
#define CONFIG_TCPS_MAX_SOCKETS         64

#define CONFIG_UDP_MAX_NUM              2

#define DEMO_SOCK_BUF_SIZE     			512
#define TCPS_TASK_PRIO					9
#define TCPC_TASK_PRIO					10
#define HTTP_CLIENT_BUFFER_SIZE			1024
#define HTTP_TASK_PRIO					11

typedef struct {
    dohome_http_t *http_client;
    tls_os_task_t task_handle;
}_http_ctrl_t;

_http_ctrl_t _http_ctrl[CONFIG_HTTP_MAX_CLIENT] = {0};

/*static void http_event_cb(httpclient_t *client, int event, void *data){
    dohome_http_t *user_client = (dohome_http_t *)client->user_arg;

    if(user_client->event_cb != NULL){
        switch (event)
        {
        case HTTP_EVENT_ERR:
            user_client->event_cb(user_client->arg, DOHOME_HTTP_EVENT_ERROR, data);
            break;
        case HTTP_EVENT_DNS_GET_IP:
            user_client->event_cb(user_client->arg, DOHOME_HTTP_EVENT_DNS_GET_IP, data);
            break;
        case HTTP_EVENT_CONNECTED:
            user_client->event_cb(user_client->arg, DOHOME_HTTP_EVENT_CONNECTED, NULL);
            break;
        case HTTP_EVENT_HEADER_SENTED:
            user_client->event_cb(user_client->arg, DOHOME_HTTP_EVENT_HEADER_SENTED, NULL);
            break;
        case DOHOME_HTTP_EVENT_RECV_HEADER:
            user_client->event_cb(user_client->arg, DOHOME_HTTP_EVENT_RECV_HEADER, NULL);
            break;
        case HTTP_EVENT_RECV_DATA:
            user_client->event_cb(user_client->arg, DOHOME_HTTP_EVENT_RECV_DATA, NULL);
            break;
        case HTTP_EVENT_FINISH:
            user_client->event_cb(user_client->arg, DOHOME_HTTP_EVENT_FINISH, data);
            break;
        default:
            break;
        }
    }
}*/


static HTTPC_RESULT http_recv_cb(httpclient_t *client, httpclient_data_t *client_data){

    dohome_http_t *user_client = (dohome_http_t *)client->user_arg;

    dohome_op_ret ret = OPRT_COM_ERROR;

    if(user_client->recv_cb){
        ret = user_client->recv_cb(user_client->arg, client_data->response_buf, client_data->response_len);
        if(ret != OPRT_OK){
            return HTTP_ERECV;
        }
    }

    return HTTP_SUCCESS;
}

static void http_connect_cb(httpclient_t *client){
    dohome_http_t *user_client = (dohome_http_t *)client->user_arg;
    
    if(user_client->connect_cb){
        user_client->connect_cb(user_client->arg);
    }
}

static void http_close_cb(httpclient_t *client){

}

static u32 http_snd_req(HTTPParameters ClientParams, HTTP_VERB verb, char *pSndData, u8 parseXmlJson, dohome_http_t *uClient)
{
    int                   nRetCode;
    u32                   nSize, nTotal = 0;
    char                 *Buffer = NULL;
    HTTP_SESSION_HANDLE   pHTTP;
    u32                   nSndDataLen ;
	u8					  temp_buff[512];
    do{
        Buffer = (char *)tls_mem_alloc(HTTP_CLIENT_BUFFER_SIZE);
        if(Buffer == NULL) {
            return HTTP_CLIENT_ERROR_NO_MEMORY;
        }
        memset(Buffer, 0, HTTP_CLIENT_BUFFER_SIZE);
        printf("HTTP Client v1.0\r\n");
        nSndDataLen = (pSndData == NULL ? 0 : strlen(pSndData));
        // Open the HTTP request handle
        pHTTP = HTTPClientOpenRequest(0);
        if(!pHTTP) {
            nRetCode =  HTTP_CLIENT_ERROR_INVALID_HANDLE;
            break;
        }
		if (verb == VerbPost) { //set header Content-Type=application/json
			if((nRetCode = HTTPClientAddRequestHeaders(pHTTP, "Content-Type", "application/json", 1))!= HTTP_CLIENT_SUCCESS){
				printf("add Content-Type header failed!\n");
			} else {
				printf("post header: Content-Type=application/json\n");
			}
		}
		if (uClient != NULL) {
			if (uClient->connect_cb != NULL) {
				uClient->connect_cb(uClient->arg);
			}
		}

        // Set the Verb
        nRetCode = HTTPClientSetVerb(pHTTP, verb);
        if(nRetCode != HTTP_CLIENT_SUCCESS) {
            break;
        }
#if TLS_CONFIG_HTTP_CLIENT_AUTH
        // Set authentication
        if(ClientParams.AuthType != AuthSchemaNone) {
            if((nRetCode = HTTPClientSetAuth(pHTTP, ClientParams.AuthType, NULL)) != HTTP_CLIENT_SUCCESS) {
                break;
            }

            // Set authentication
            if((nRetCode = HTTPClientSetCredentials(pHTTP, ClientParams.UserName, ClientParams.Password)) != HTTP_CLIENT_SUCCESS) {
                break;
            }
        }
#endif //TLS_CONFIG_HTTP_CLIENT_AUTH
#if TLS_CONFIG_HTTP_CLIENT_PROXY
        // Use Proxy server
        if(ClientParams.UseProxy == TRUE) {
            if((nRetCode = HTTPClientSetProxy(pHTTP, ClientParams.ProxyHost, ClientParams.ProxyPort, NULL, NULL)) != HTTP_CLIENT_SUCCESS) {
                break;
            }
        }
#endif //TLS_CONFIG_HTTP_CLIENT_PROXY
		printf("~~> len=%d, sendData=%s, url=%s\n", nSndDataLen, pSndData, ClientParams.Uri);
        if((nRetCode = HTTPClientSendRequest(pHTTP, ClientParams.Uri, pSndData, nSndDataLen, verb == VerbPost || verb == VerbPut, 0, 0)) != HTTP_CLIENT_SUCCESS) {
            printf("send request failed: %d\n", nRetCode);
			break;
        }
        // Retrieve the the headers and analyze them
        if((nRetCode = HTTPClientRecvResponse(pHTTP, 30)) != HTTP_CLIENT_SUCCESS) {
            break;
        }
        printf("Start to receive data from remote server...\r\n");

        // Get the data until we get an error or end of stream code
        while(nRetCode == HTTP_CLIENT_SUCCESS || nRetCode != HTTP_CLIENT_EOS) {
            // Set the size of our buffer
            nSize = HTTP_CLIENT_BUFFER_SIZE;
			memset(temp_buff, 0, 512);
            // Get the data
            nRetCode = HTTPClientReadData(pHTTP, temp_buff, nSize, 300, &nSize);
            if(nRetCode != HTTP_CLIENT_SUCCESS && nRetCode != HTTP_CLIENT_EOS) {
                break;
			}
			memcpy(Buffer+nTotal, temp_buff, nSize);
            nTotal += nSize;
			if (nTotal > HTTP_CLIENT_BUFFER_SIZE) {
				printf("client buff size is not enough!\n");
				break;
			}
        }
		printf("client recv: %s\n", Buffer);
    }
    while(0);   // Run only once
	if (uClient != NULL) {
		uClient->resp_len = nTotal;
		memset(uClient->resp_buf, 0, uClient->resp_buf_len);
		memcpy(uClient->resp_buf, Buffer, nTotal);
		if (uClient->recv_cb != NULL) {
			uClient->recv_cb(uClient->arg, Buffer, nTotal);
		}
	}
    tls_mem_free(Buffer);

    if(pHTTP) {
        HTTPClientCloseRequest(&pHTTP);
	}
    if(ClientParams.Verbose == TRUE) {
        printf("\n\nHTTP Client terminated %d (got %d b)\n\n", nRetCode, nTotal);
    }

    return nRetCode;
}

static u32 http_post(HTTPParameters ClientParams, char *pSndData, dohome_http_t *uClient)
{
    return http_snd_req(ClientParams, VerbPost, pSndData, 0, uClient);
}

static u32 http_get(HTTPParameters ClientParams, dohome_http_t *uClient)
{
    return http_snd_req(ClientParams, VerbGet, NULL, 0, uClient);
}

DOHOME_STATIC void http_task(void *arg){
	_http_ctrl_t *http_ctrl = (_http_ctrl_t *)arg;
    dohome_http_t *user_client = http_ctrl->http_client;

    httpclient_t http_client = {0};
    httpclient_data_t client_data = {0};

    http_client.user_arg = user_client;
    
    client_data.post_buf = user_client->post_buf;
    client_data.post_buf_len = user_client->post_buf_len;
    client_data.response_buf = user_client->resp_buf;
    client_data.response_buf_len = user_client->resp_buf_len;
    //httpclient_set_custom_header(&http_client, user_client->header);

    if(user_client->method == DOHOME_HTTP_METHOD_GET){
        //httpclient_get_request(&http_client, user_client->url, &client_data, &client_cb);
		HTTPParameters httpParams;
		memset(&httpParams, 0, sizeof(HTTPParameters));
		httpParams.Uri = (char *)tls_mem_alloc(128);
		if(httpParams.Uri == NULL) {
			printf("Uri malloc error.\n");
			return;
		}
		memset(httpParams.Uri, 0, 128);
		sprintf(httpParams.Uri, "%s", user_client->url);
		httpParams.Verbose = TRUE;
		printf("Get Location: %s\n", httpParams.Uri);
		http_get(httpParams, user_client);
		tls_mem_free(httpParams.Uri);
    }else if(user_client->method == DOHOME_HTTP_METHOD_POST){
        //httpclient_post_request(&http_client, user_client->url, &client_data, &client_cb);
		HTTPParameters httpParams;
		memset(&httpParams, 0, sizeof(HTTPParameters));
		httpParams.Uri = (char *)tls_mem_alloc(128);
		if(httpParams.Uri == NULL) {
			printf("uri malloc error.\n");
			return;
		}
		memset(httpParams.Uri, 0, 128);
		sprintf(httpParams.Uri, "%s", user_client->url);
		DOHOME_LOG_D("Post Location: %s\n", httpParams.Uri);
		httpParams.Verbose = TRUE;
		http_post(httpParams, user_client->post_buf, user_client);
		tls_mem_free(httpParams.Uri);
    }

    //user_client->resp_len = client_data.response_content_len - client_data.retrieve_len;
    if(user_client->close_cb){
        user_client->close_cb(user_client, 200 /*http_client.response_code*/);
    }
}


dohome_op_ret dohome_hal_http_connect(dohome_http_t *client){

    if(client == NULL){
        return OPRT_COM_ERROR;
    }

	DOHOME_UINT8_T index = 0;
    DOHOME_CHAR_T task_name[] = "http_client0";
    
    for (index = 0; index < CONFIG_HTTP_MAX_CLIENT; index++)
    {
        if(_http_ctrl[index].task_handle == NULL){
            break;
        }
    }
    if(index == CONFIG_HTTP_MAX_CLIENT){
        return OPRT_COM_ERROR;
    }

    _http_ctrl[index].http_client = client;
    task_name[sizeof("http_client0") - 2] = index + '0';
	//http_task(&_http_ctrl[index]);
	tls_os_task_create(&(_http_ctrl[index].task_handle), task_name,
                       http_task,
                       (void *)(&_http_ctrl[index]),
                       NULL,
                       1280,    
                       HTTP_TASK_PRIO,
                       0);

    return OPRT_OK;
}

typedef struct {
    DOHOME_INT_T sockfd;
    DOHOME_UINT8_T is_connect;
    dohome_tcpc_t *tcp_client;
    tls_os_task_t task_handle;
}_tcpc_ctrl_t;

_tcpc_ctrl_t _tcpc_ctrl_list[CONFIG_TCPC_MAX_CLIENT] = {0};

//设置TCP keepAlive参数
DOHOME_STATIC dohome_op_ret TCPSetKeepAlive( DOHOME_INT_T sockfd, DOHOME_INT_T keepAlive, DOHOME_INT_T keepIdle, DOHOME_INT_T keepInterval, DOHOME_INT_T keepCount ) {

	DOHOME_INT_T tvKeepAlive = keepAlive;
	DOHOME_INT_T tvKeepIdle = keepIdle;
	DOHOME_INT_T tvKeepInterval = keepInterval;
	DOHOME_INT_T tvKeepCount = keepCount;

	if ( setsockopt( sockfd, SOL_SOCKET, SO_KEEPALIVE, ( void * )&tvKeepAlive, sizeof( int ) ) < 0 ) {
		DOHOME_LOG_E("Set setsockopt keep alive failed");
	}
	if ( setsockopt( sockfd, IPPROTO_TCP, TCP_KEEPIDLE, ( void * )&tvKeepIdle, sizeof( int ) ) < 0 ) {
		DOHOME_LOG_E("Set setsockopt keep idle failed");
	}
	if ( setsockopt( sockfd, IPPROTO_TCP, TCP_KEEPINTVL, ( void * )&tvKeepInterval, sizeof( int ) ) < 0 ) {
		DOHOME_LOG_E("Set setsockopt keep interval failed");
	}
	if ( setsockopt( sockfd, IPPROTO_TCP, TCP_KEEPCNT, ( void * )&tvKeepCount, sizeof( int ) ) < 0 ) {
		DOHOME_LOG_E("Set setsockopt keep count failed");
	}
    DOHOME_LOG_D("TCPSetKeepAlive FINISH");
	return OPRT_OK;
}


DOHOME_STATIC void tcpc_task(void *arg){
	int ret = 0;
	_tcpc_ctrl_t *tcp_ctrl = (_tcpc_ctrl_t *)arg;
    dohome_tcpc_t *client = tcp_ctrl->tcp_client;
	DOHOME_CHAR_T databuff[512] = {0};

	struct sockaddr_in pin;
    memset(&pin, 0, sizeof(struct sockaddr));
    pin.sin_family = AF_INET;
	struct in_addr inet_ip_addr;
	int ip_addr = inet_aton(client->host, &inet_ip_addr);
    pin.sin_addr.s_addr = inet_ip_addr.s_addr;
    pin.sin_port = htons(client->port);
	//memcpy((void *)&pin.sin_addr.s_addr, (void *)hostinfo->h_addr, (DOHOME_INT8_T)hostinfo->h_length);
	int sockfd = -1;

	while (1) {
		sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
		DOHOME_LOG_D("\ncreate tcp client socket fd: %d\n", sockfd);
		if (sockfd < 0) {
			DOHOME_LOG_E("creat socket fail, errno:%d\n", errno);
			break;
		}
		tcp_ctrl->sockfd = sockfd;

		DOHOME_LOG_D("\nsocket num=%d connect\n", sockfd);
		if (connect(sockfd, (struct sockaddr *)&pin, sizeof(struct sockaddr)) != 0) {
			printf("connect failed! socket num=%d\n", tcp_ctrl->sockfd);
			closesocket(sockfd);
			tcp_ctrl->sockfd = 0;
			break;
		}
		DOHOME_LOG_I("tcpc connected");
		tcp_ctrl->is_connect = 1;
		if(client->connect_cb){
			client->connect_cb(client->arg);
		}

		for (;;) {
			if (tcp_ctrl->is_connect) {
				ret = 0;
				memset(databuff, 0x00, sizeof(databuff));
				ret = recv(sockfd, databuff, sizeof(databuff), 0);

				if(ret > 0) { //get len=ret
					if(client->recv_cb){
						client->recv_cb(client->arg, databuff, ret);
					}
				} else if (ret == 0) {
					DOHOME_LOG_E("tcpc recv len = 0");
					break;
				} 
				if (ret < 0) {
					if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
						
					} else {
						DOHOME_LOG_E("tcpc recv len < 0 & errno:%d", errno);
						break;
					}
				}
			}
			tls_os_time_delay(1);
		}

		tcp_ctrl->is_connect = 0;
		closesocket(sockfd);
		DOHOME_LOG_D("closesocket: %d\n", sockfd);
		tcp_ctrl->sockfd = 0;
		sockfd = -1;
		if(client->disconnect_cb){
			client->disconnect_cb(client->arg);
		}
	}

	DOHOME_LOG_E("delete tcp client task!");
	//tls_os_task_del_by_task_handle(tcp_ctrl->task_handle, NULL);
	tcp_ctrl->task_handle = NULL;
}

dohome_op_ret dohome_hal_tcpc_reconnect(dohome_tcpc_t *client){
    DOHOME_UINT8_T index = 0;
	for (index = 0; index < CONFIG_TCPC_MAX_CLIENT; index++) {
        if(_tcpc_ctrl_list[index].tcp_client == client){
            break;
        }
    }

    if(index == CONFIG_TCPC_MAX_CLIENT){
        return OPRT_COM_ERROR;
    }

    if(_tcpc_ctrl_list[index].sockfd < 0){
        return OPRT_COM_ERROR;
    }

    DOHOME_INT8_T sockfd = _tcpc_ctrl_list[index].sockfd;
    
    _tcpc_ctrl_list[index].sockfd = -1;
    close(sockfd);
    return OPRT_OK;
}

dohome_op_ret dohome_hal_tcpc_send(dohome_tcpc_t *client, DOHOME_CHAR_T *data, DOHOME_UINT16_T len){
    DOHOME_UINT8_T index = 0;
    DOHOME_INT_T send_len = 0;
	for (index = 0; index < CONFIG_TCPC_MAX_CLIENT; index++) {
        if(_tcpc_ctrl_list[index].tcp_client == client){
            break;
        }
    }

    if(index == CONFIG_TCPC_MAX_CLIENT){
        return OPRT_COM_ERROR;
    }

    if(_tcpc_ctrl_list[index].is_connect){
        send_len = send(_tcpc_ctrl_list[index].sockfd, data, len, 0);
        if(send_len != len)
        {
            if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR ) {
				DOHOME_LOG_E("tcpc send other error & errno:%d", errno);
            } else {
                DOHOME_LOG_E("tcpc send error & errno:%d", errno);
                DOHOME_INT8_T sockfd = _tcpc_ctrl_list[index].sockfd;
                _tcpc_ctrl_list[index].sockfd = -1;
                close(sockfd);
                return OPRT_COM_ERROR;
            }
        }
    }else{
        return OPRT_COM_ERROR;
    }
    return OPRT_OK;
}

dohome_op_ret dohome_hal_tcpc_create(dohome_tcpc_t *client){
	DOHOME_LOG_D("create a TCP client\n");
    if(client == NULL){
		DOHOME_LOG_E("params is NULL\n");
        return OPRT_COM_ERROR;
    }

	DOHOME_UINT8_T index = 0;
    DOHOME_UINT8_T null_index = CONFIG_TCPC_MAX_CLIENT;
    DOHOME_UINT8_T same_index = CONFIG_TCPC_MAX_CLIENT;
    DOHOME_CHAR_T task_name[] = "tcp_client0";

    for (index = 0; index < CONFIG_TCPC_MAX_CLIENT; index++)
    {
        if(null_index == CONFIG_TCPC_MAX_CLIENT && _tcpc_ctrl_list[index].tcp_client == NULL){
            null_index = index;
        }
        if(_tcpc_ctrl_list[index].tcp_client == client){
            same_index = index;
            break;
        }
    }

    if(same_index == CONFIG_TCPC_MAX_CLIENT && null_index == CONFIG_TCPC_MAX_CLIENT){
        DOHOME_LOG_E("tcpc create error");
        return OPRT_COM_ERROR;
    }

    if(same_index != CONFIG_TCPC_MAX_CLIENT){
        index = same_index;
        if(_tcpc_ctrl_list[index].task_handle){
            tls_os_task_del_by_task_handle(_tcpc_ctrl_list[index].task_handle, NULL); //vTaskDelete(_tcpc_ctrl_list[index].task_handle);
            _tcpc_ctrl_list[index].task_handle = NULL;
        }
        if(_tcpc_ctrl_list[index].sockfd){
            close(_tcpc_ctrl_list[index].sockfd);
            _tcpc_ctrl_list[index].sockfd = -1;
        }
        if(_tcpc_ctrl_list[index].is_connect == 1){
            _tcpc_ctrl_list[index].is_connect = 0;
            if(_tcpc_ctrl_list[index].tcp_client->disconnect_cb){
                _tcpc_ctrl_list[index].tcp_client->disconnect_cb(client->arg);
            }
        }
    }else{
        index = null_index;
        _tcpc_ctrl_list[index].sockfd = -1;
        _tcpc_ctrl_list[index].is_connect = 0;
        _tcpc_ctrl_list[index].tcp_client = client;
    }
	//printf("~~> 333 %s:%d\n", client->host, client->port);
	//dohome_tcpc_t *client = _tcpc_ctrl_list[index].tcp_client;
	/*struct hostent *hostinfo = (struct hostent *)gethostbyname(client->host);
	if (hostinfo == NULL) {
		printf("get hostinfo failed!\n");
		return OPRT_COM_ERROR;
	}*/
	

    task_name[sizeof("tcp_client0") - 2] = index + '0'; 
    //xTaskCreate(tcpc_task, task_name, CONFIG_TCPC_STACK_SIZE, &_tcpc_ctrl_list[index], CONFIG_TCPC_STACK_PRIORITY, &_tcpc_ctrl_list[index].task_handle);
	tls_os_task_create(&(_tcpc_ctrl_list[index].task_handle), task_name,
                       tcpc_task,
                       (void *)(&_tcpc_ctrl_list[index]),
                       NULL,
                       2048,    
                       TCPC_TASK_PRIO,
                       0);

    return OPRT_OK;
}

dohome_op_ret dohome_hal_tcpc_delete(dohome_tcpc_t *client){
    DOHOME_UINT8_T index = 0;
    for (index = 0; index < CONFIG_TCPC_MAX_CLIENT; index++) {
        if(_tcpc_ctrl_list[index].tcp_client == client){
            break;
        }
    }

    if(index == CONFIG_TCPC_MAX_CLIENT){
        DOHOME_LOG_E("tcpc delete error");
        return OPRT_COM_ERROR;
    }

    if(_tcpc_ctrl_list[index].task_handle){
        tls_os_task_del_by_task_handle(_tcpc_ctrl_list[index].task_handle, NULL); //vTaskDelete(_tcpc_ctrl_list[index].task_handle);
        _tcpc_ctrl_list[index].task_handle = NULL;
    }
    if(_tcpc_ctrl_list[index].sockfd){
        close(_tcpc_ctrl_list[index].sockfd);
        _tcpc_ctrl_list[index].sockfd = -1;
    }
    if(_tcpc_ctrl_list[index].is_connect == 1){
        _tcpc_ctrl_list[index].is_connect = 0;
        if(_tcpc_ctrl_list[index].tcp_client->disconnect_cb){
            _tcpc_ctrl_list[index].tcp_client->disconnect_cb(client->arg);
        }
    }

    _tcpc_ctrl_list[index].tcp_client = NULL;
    return OPRT_OK;
}

typedef struct {
    dohome_tcps_t *tcp_server;
	tls_os_task_t task_handle;
    DOHOME_INT8_T server_sockfd;
    DOHOME_UINT8_T client_num;
    DOHOME_INT_T client_sockfd[CONFIG_TCPS_MAX_CLIENT];
}_tcps_ctrl_t;

_tcps_ctrl_t _tcps_ctrl_list[CONFIG_TCPS_MAX_SERVER] = {0};

DOHOME_STATIC void tcps_task(void *arg)
{
	_tcps_ctrl_t *tcps_ctrl = (_tcps_ctrl_t *)arg;
    dohome_tcps_t *server = tcps_ctrl->tcp_server;
	
    char sock_rx[DEMO_SOCK_BUF_SIZE] = {0};
    struct sockaddr_in server_addr; // server address information
    struct sockaddr_in client_addr; // connector's address information
    socklen_t sin_size;
	int server_fd = -1;
	int new_fd = -1;
    int ret;	
	while(1) {
    	if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        	printf("create socket fail, errno :%d\n",errno); //DOHOME_LOG_W
        	break;
    	}
    	
    	server_addr.sin_family = AF_INET;   
    	server_addr.sin_port = htons(server->port);
    	server_addr.sin_addr.s_addr = ((u32) 0x00000000UL);   
    	memset(server_addr.sin_zero, '\0', sizeof(server_addr.sin_zero));

    	if (bind(server_fd, (struct sockaddr *) &server_addr, sizeof(server_addr)) != 0) {
        	printf("bind fail, errno:%d\n",errno);
			break;
   	 	}
		
    	if (listen(server_fd, 1) != 0) {
        	printf("listen fail,errno:%d\n",errno);
        	break;
    	}
		tcps_ctrl->server_sockfd = server_fd;
    	printf("listen port %d\n", server->port);
    	sin_size = sizeof(client_addr);
		new_fd = accept(server_fd, (struct sockaddr *) &client_addr, &sin_size);
        printf("accept newfd = %d\n",new_fd);
			
        if (new_fd < 0) {
              printf("accept fail,errno:%d\n",errno);
              break;
        }
		
		for (int i = 0; i < CONFIG_TCPS_MAX_CLIENT; i++) {
			if ((tcps_ctrl->client_sockfd)[i] >= 0) {
				(tcps_ctrl->client_sockfd)[i] = new_fd;
			}
		}
		
		if(server->connect_cb){
            server->connect_cb(server->arg, new_fd);
        }
		
    	while (1) {
        	memset(sock_rx, 0, DEMO_SOCK_BUF_SIZE);
            ret = recv(new_fd, sock_rx, sizeof(sock_rx)-1, 0);
			if(ret == 0) {
            	printf("connection disconnect\n");
				break;
            } else if(ret < 0) {
				printf("receive fail errno:%d\n",errno);
				break;
			} else {     
            	sock_rx[ret] = 0;
				printf("\nReceive %d bytes from %s\n", ret, inet_ntoa(client_addr.sin_addr.s_addr));
				printf("%s\n", sock_rx);
				if(server->recv_cb){
                    server->recv_cb(server->arg, new_fd, sock_rx, ret);
                }
            }
			tls_os_time_delay(5);
   	 	}
		if(new_fd != -1) {
			printf("shutting down socket and restaring...\n");
			shutdown(new_fd, 0);
			closesocket(new_fd);
			
			tcps_ctrl->client_num--;
            if(server->disconnect_cb){
                server->disconnect_cb(server->arg, new_fd);
            }
            for (DOHOME_UINT8_T index = 0; index < CONFIG_TCPS_MAX_CLIENT; index++) {
                if(tcps_ctrl->client_sockfd[index] == new_fd){
                    tcps_ctrl->client_sockfd[index] = -1;
                    break;
                }
            }
		}
	}

	tls_os_task_del_by_task_handle(tcps_ctrl->task_handle, NULL);
	tcps_ctrl->task_handle = NULL;
	return 0;
}

dohome_op_ret dohome_hal_tcps_send(dohome_tcps_t *server, DOHOME_UINT8_T client_id, DOHOME_CHAR_T *data, DOHOME_UINT16_T len){

    DOHOME_INT_T send_len = 0;

	/**/
	
	DOHOME_INT_T i = 0;
    DOHOME_INT_T index = 0;

    for (index = 0; index < CONFIG_TCPC_MAX_CLIENT; index++)
    {
        if(_tcps_ctrl_list[index].tcp_server == server){
            break;
        }
    }

    if(index == CONFIG_TCPC_MAX_CLIENT){
        DOHOME_LOG_E("tcps send pram(server) error");
        return OPRT_COM_ERROR;
    }

    for (i = 0; i < CONFIG_TCPS_MAX_CLIENT; i++)
    {
        if(_tcps_ctrl_list[index].client_sockfd[i] == client_id){
            break;
        }
    }

    if(i == CONFIG_TCPC_MAX_CLIENT){
        DOHOME_LOG_E("tcps send pram(client_id) error");
        return OPRT_COM_ERROR;
    }
	
	DOHOME_INT_T ret = send(client_id, data, len, 0);
	if (ret < 0) {
		printf("Error occured during sending, errno:%d\n",errno);
	}

    return OPRT_OK;
}

dohome_op_ret dohome_hal_tcps_create(dohome_tcps_t *server){
    if(server == NULL){
        return OPRT_COM_ERROR;
    }

    DOHOME_UINT8_T index = 0;
    DOHOME_UINT8_T null_index = CONFIG_TCPS_MAX_SERVER;
    DOHOME_UINT8_T same_index = CONFIG_TCPS_MAX_SERVER;
    DOHOME_CHAR_T task_name[] = "tcp_server0";

    for (index = 0; index < CONFIG_TCPS_MAX_SERVER; index++)
    {
        if(null_index == CONFIG_TCPS_MAX_SERVER && _tcps_ctrl_list[index].tcp_server == NULL){
            null_index = index;
        }
        if(_tcps_ctrl_list[index].tcp_server == server){
            same_index = index;
            break;
        }
    }

    if(same_index == CONFIG_TCPS_MAX_SERVER && null_index == CONFIG_TCPS_MAX_SERVER){
        DOHOME_LOG_E("tcps create error");
        return OPRT_COM_ERROR;
    }

    if(same_index != CONFIG_TCPS_MAX_SERVER){
        DOHOME_LOG_E("tcps is exist");
        return OPRT_COM_ERROR;
    }else{
        index = null_index;
        _tcps_ctrl_list[index].client_num = 0;
        _tcps_ctrl_list[index].tcp_server = server;
    }

    task_name[sizeof("tcp_server0") - 2] = index + '0'; 
    //xTaskCreate(tcps_task, task_name, CONFIG_TCPS_STACK_SIZE, &_tcps_ctrl_list[index], CONFIG_TCPS_STACK_PRIORITY, &_tcpc_ctrl_list[index].task_handle);
	tls_os_task_create(&(_tcps_ctrl_list[index].task_handle), task_name,
                       tcps_task,
                       (void *)(&_tcps_ctrl_list[index]),
                       NULL,
                       1536, // 任务栈的大小     
                       TCPS_TASK_PRIO,
                       0);

    return OPRT_OK;
}


dohome_op_ret dohome_hal_tcps_delete(dohome_tcps_t *server){
    DOHOME_UINT8_T index = 0;
	
    for (index = 0; index < CONFIG_TCPC_MAX_CLIENT; index++)
    {
        if(_tcps_ctrl_list[index].tcp_server == server){
            break;
        }
    }

    if(index == CONFIG_TCPC_MAX_CLIENT){
        DOHOME_LOG_E("tcps delete error");
        return OPRT_COM_ERROR;
    }

    if(_tcps_ctrl_list[index].task_handle){
        tls_os_task_del_by_task_handle(_tcps_ctrl_list[index].task_handle, NULL); //vTaskDelete(_tcps_ctrl_list[index].task_handle);
        _tcps_ctrl_list[index].task_handle = NULL;
    }

    for (DOHOME_UINT8_T i = 0; i < CONFIG_TCPS_MAX_CLIENT; i++)
    {
        if(_tcps_ctrl_list[index].client_sockfd[i] != -1){
            close(_tcps_ctrl_list[index].client_sockfd[i]);
            if(_tcps_ctrl_list[index].tcp_server->disconnect_cb){
                _tcps_ctrl_list[index].tcp_server->disconnect_cb(_tcps_ctrl_list[index].tcp_server->arg, _tcps_ctrl_list[index].client_sockfd[i]);
                _tcps_ctrl_list[index].client_sockfd[i] = -1;
            }
        }
    }

    if(_tcps_ctrl_list[index].server_sockfd != -1){
        close(_tcps_ctrl_list[index].server_sockfd);
        _tcps_ctrl_list[index].server_sockfd = -1;
    }

    _tcps_ctrl_list[index].tcp_server = NULL;
	
    return OPRT_OK;
}

typedef struct {
    dohome_udp_t *udp;
    struct udp_pcb *pcb;
}_udp_ctrl_t;

_udp_ctrl_t _udp_ctrl_list[CONFIG_UDP_MAX_NUM] = {0};

static void udp_raw_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, short unsigned int port){
    
    if(arg == NULL ){
        return;
    }

    _udp_ctrl_t *udp_ctrl = (_udp_ctrl_t *)arg;

    dohome_upd_dest_t upd_dest = {0};

    upd_dest.ip_type = DOHOME_IP_TYPE_IPv4;
    memcpy(&upd_dest.addr.ip_v4.addr, addr, 4);
    upd_dest.port = port;

    udp_ctrl->udp->recv_cb(udp_ctrl->udp->arg, upd_dest, p->payload, p->len);
    pbuf_free(p);
}


dohome_op_ret dohome_hal_udp_listen(dohome_udp_t *udp){

    struct udp_pcb *pcb;
    DOHOME_UINT8_T index = 0;
    DOHOME_UINT8_T null_index = CONFIG_UDP_MAX_NUM;
    DOHOME_UINT8_T same_index = CONFIG_UDP_MAX_NUM;

    for (index = 0; index < CONFIG_UDP_MAX_NUM; index++)
    {
        if(null_index == CONFIG_UDP_MAX_NUM && _udp_ctrl_list[index].udp == NULL){
            null_index = index;
        }
        if(_udp_ctrl_list[index].udp == udp){
            same_index = index;
            break;
        }
    }

    if(same_index == CONFIG_UDP_MAX_NUM && null_index == CONFIG_UDP_MAX_NUM){
        DOHOME_LOG_E("udp listen error");
        return OPRT_COM_ERROR;
    }

    if(same_index != CONFIG_UDP_MAX_NUM){
        DOHOME_LOG_E("udp is exist");
       return OPRT_COM_ERROR;
    }else{
        index = null_index;
        _udp_ctrl_list[index].udp = udp;
    }


	pcb = (struct udp_pcb *)udp_new();
    _udp_ctrl_list[index].pcb = pcb;

	udp_bind(pcb, IP_ADDR_ANY, udp->port);
	/* no need to loop forever */
	udp_recv(pcb, udp_raw_recv, &_udp_ctrl_list[index]);

    return OPRT_OK;
}


dohome_op_ret dohome_hal_udp_send(dohome_udp_t *udp, dohome_upd_dest_t dest, DOHOME_CHAR_T *data, DOHOME_UINT16_T len){

    ip_addr_t tmp_addr = {0};
    DOHOME_UINT8_T index = 0;

    for (index = 0; index < CONFIG_UDP_MAX_NUM; index++)
    {
        if(_udp_ctrl_list[index].udp == udp){
            break;
        }
    }

    if(index == CONFIG_UDP_MAX_NUM){
        DOHOME_LOG_E("udp send pram(udp) error");
        return OPRT_COM_ERROR;
    }

    /*if(dest.ip_type == DOHOME_IP_TYPE_IPv4){
        memcpy(&tmp_addr.addr, &dest.addr.ip_v4.addr, 4);
    }*/
	memcpy(&tmp_addr.addr, &dest.addr.ip_v4.addr, 4);

    struct pbuf *tmp_buf = pbuf_alloc(PBUF_RAW, len, PBUF_ROM); //pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM);
	if (tmp_buf == NULL) {
		return OPRT_MALLOC_FAILED;
	}

    //pbuf_take(tmp_buf, data, len);
	printf("~~> ip:%x, port: %d\n", tmp_addr.addr, dest.port);
	tmp_buf->payload = (void *)data;
    udp_sendto(_udp_ctrl_list[index].pcb, tmp_buf, &tmp_addr, dest.port);
	udp_disconnect(_udp_ctrl_list[index].pcb);
    pbuf_free(tmp_buf);
    return OPRT_OK; 
}

#endif